/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */
package com.googlecode.ivybeans.module;

import com.googlecode.ivybeans.module.classpath.ClassPathScope;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ant.AntBuildExtender;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.Exceptions;
import org.openide.xml.XMLUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 *
 * @author lforet
 */
public class IvyBuildHelper {

    private static IvyBuildHelper instance;

    private IvyBuildHelper() {
    }

    public static IvyBuildHelper getInstance() {
        if (instance == null) {
            instance = new IvyBuildHelper();
        }
        return instance;
    }

    public void createIvyImpl(Project project, File descriptorFile, File settingsFile, URL settingsURL) {
        try {
            clean(project);
            FileObject projDir = project.getProjectDirectory();
            FileObject transformFO = FileUtil.getConfigFile("Templates/ivybeans/ivyreport2properties.xsl"); // NOI18N
            assert transformFO != null;
            FileObject ivyTransform = FileUtil.copyFile(transformFO, projDir.getFileObject("nbproject"), "ivyreport2properties"); // NOI18N

            FileObject templateFO = FileUtil.getConfigFile("Templates/ivybeans/ivy-impl.xml"); // NOI18N
            assert templateFO != null;
            FileObject ivyBuildFile = FileUtil.copyFile(templateFO, projDir.getFileObject("nbproject"), "ivy-impl"); // NOI18N
            Document ivyBuildDoc = XMLUtil.parse(new InputSource(ivyBuildFile.getInputStream()), false, true, null, null);

            // Issue 22 http://code.google.com/p/ivybeans/issues/detail?id=22
            // Map correctly different ant classpath with Ivy configuration
            NodeList foreachElements = ivyBuildDoc.getElementsByTagName("FOREACHSCOPE");
            assert 1 == foreachElements.getLength() : foreachElements.getLength();
            Element foreachElement = (Element) foreachElements.item(0);
            Node insertWhere = foreachElement.getNextSibling();
            Node insertOwner = foreachElement.getParentNode();
            foreachElement.getParentNode().removeChild(foreachElement); // we don't want it, just the prototypes inside it

            NodeList pathConvertElements = foreachElement.getElementsByTagName("pathconvert");
            assert 1 == pathConvertElements.getLength() : pathConvertElements.getLength();
            Element pathconvertElement = (Element) pathConvertElements.item(0);

            IvyLibraryController ivyLibraryController = project.getLookup().lookup(IvyLibraryController.class);
            for(ClassPathScope scope : ClassPathScope.values()) {
                final String[] confs = ivyLibraryController.getConfigurationMapping().getConfiguration(scope);
                if(confs == null || confs.length == 0) {
                    Element emptyProperty = ivyBuildDoc.createElement("property");
                    emptyProperty.setAttribute("name", pathconvertElement.getAttribute("property").replace("{SCOPE}", scope.name()));
                    emptyProperty.setAttribute("value", "");
                    insertOwner.insertBefore(emptyProperty, insertWhere);
                } else {
                    Element clonedpathconvert = (Element) pathconvertElement.cloneNode(true);
                    clonedpathconvert.setAttribute("property", clonedpathconvert.getAttribute("property").replace("{SCOPE}", scope.name()));
                    Element pathElement = (Element)clonedpathconvert.getElementsByTagName("path").item(0);
                    clonedpathconvert.removeChild(pathElement); // we're going to append modified versions
                    for(String conf : confs) {
                        Element pathClone = (Element) pathElement.cloneNode(true);
                        pathClone.setAttribute("path", pathClone.getAttribute("path").replace("{EACHCONFFORSCOPE}", conf));
                        clonedpathconvert.appendChild(pathClone);
                    }
                    insertOwner.insertBefore(clonedpathconvert, insertWhere);
                }
            }
            final FileOutputStream out = new FileOutputStream(FileUtil.toFile(ivyBuildFile));
            try {
                XMLUtil.write(ivyBuildDoc, out, "UTF-8"); // NOI18N
            } finally {
                if( out != null) {
                    try {
                        out.close();
                    } catch (IOException ignore) {
                    }
                }
            }
            addBuildExtension(project);
        } catch (IOException ex) {
            Exceptions.printStackTrace(ex);
        } catch (SAXException ex) {
            Exceptions.printStackTrace(ex);
        }
    }

    public void clean(Project project) {
        try {
            FileObject projDir = project.getProjectDirectory();
            FileObject ivyBuildFile = projDir.getFileObject("nbproject/ivy-impl.xml"); // NOI18N
            if (ivyBuildFile != null) {
                FileUtil.toFile(ivyBuildFile).delete();
                removeBuildExtension(project);
            }
            FileObject xslFile = projDir.getFileObject("nbproject/ivyreport2properties.xsl"); // NOI18N
            if (xslFile != null) {
                FileUtil.toFile(xslFile).delete();
            }
        } catch (IOException iOException) {
            Exceptions.printStackTrace(iOException);
        }
    }

    private void addBuildExtension(Project project) throws IOException {
        FileObject projDir = project.getProjectDirectory();
        FileObject ivyBuildFile = projDir.getFileObject("nbproject/ivy-impl.xml"); // NOI18N
        AntBuildExtender extender = project.getLookup().lookup(AntBuildExtender.class);
        assert extender != null;
        assert ivyBuildFile != null;
        if (extender.getExtension("ivy") == null) { // NOI18N
            AntBuildExtender.Extension ext = extender.addExtension("ivy", ivyBuildFile); // NOI18N
            // JSEProject extensible targets :  "-do-init", "-init-check", "-post-clean", "jar", "-pre-pre-compile","-do-compile","-do-compile-single" 
            ext.addDependency("-do-init", "-ivy-retrieve"); // NOI18N
//            ext.addDependency("-do-compile-single", "-ivy-retrieve"); // NOI18N
            ext.addDependency("jar", "-ivy-publish"); // NOI18N
            ext.addDependency("-post-clean", "-ivy-clean"); // NOI18N
        }
//        ProjectManager.getDefault().saveProject(project);
    }

    private void removeBuildExtension(Project project) throws IOException {
        AntBuildExtender extender = project.getLookup().lookup(AntBuildExtender.class);
        assert extender != null;
        if (extender.getExtension("ivy") != null) { // NOI18N
            extender.removeExtension("ivy"); // NOI18N
        }
//        ProjectManager.getDefault().saveProject(project);
    }
}
